/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */
package org.jiopi.ibean.module.remote.common;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * bytes to number, number to bytes
 * bytes to hex , hex to bytes
 *
 */
public class ByteUtil {

	private static byte uniteBytes(byte src0, byte src1) {
		byte _b0 = Byte.decode("0x" + new String(new byte[]{src0}));
		_b0 = (byte) (_b0 << 4);
		byte _b1 = Byte.decode("0x" + new String(new byte[]{src1}));
        return (byte) (_b0 ^ _b1);
	}

	/**
	 * 将hex字符串转换为byte[]数组
	 * @param src
	 * @return
	 */
	public static byte[] hexToByte(String src) {
		byte[] tmp = src.getBytes();
		byte[] ret = new byte[tmp.length / 2];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
		}
		return ret;
	}

	/**
	 * Turns an array of bytes into a String representing each byte as an
	 * unsigned hex number.
	 * <p>
	 * Method by Santeri Paavolainen, Helsinki Finland 1996<br>
	 * (c) Santeri Paavolainen, Helsinki Finland 1996<br>
	 * Distributed under LGPL.
	 *
	 * @param hash
	 *            an rray of bytes to convert to a hex-string
	 * @return generated hex string
	 */
	public static String toHex(byte hash[]) {
		StringBuffer buf = new StringBuffer(hash.length * 2);
		int i;

		for (i = 0; i < hash.length; i++) {
			if (((int) hash[i] & 0xff) < 0x10) {
				buf.append("0");
			}
			buf.append(Long.toString((int) hash[i] & 0xff, 16));
		}
		return buf.toString();
	}

	/**
	 * @param value
	 * @return
	 */
	public static byte[] getLittleBytesByLong( long value ) {
		return ByteUtil.getBytesByLong( value, false );
	}

	/**
	 * @param value
	 * @return
	 */
	public static byte[] getBigBytesByLong( long value ) {
		return ByteUtil.getBytesByLong( value, true );
	}

	/**
	 * @param value
	 * @param bigEndian
	 * @return
	 */
	private static byte[] getBytesByLong( long value, boolean bigEndian ) {
		ByteBuffer bb = ByteBuffer.allocate( 8 );
		if ( !bigEndian )
			bb.order( ByteOrder.LITTLE_ENDIAN );
		bb.putLong( value );
        return bb.array( );
	}

	/**
	 * @param value
	 * @return
	 */
	public static byte[] getLittleBytesByInt( int value ) {
		return ByteUtil.getBytesByInt( value, false );
	}

	/**
	 * @param value
	 * @return
	 */
	public static byte[] getBigBytesByInt( int value ) {
		return ByteUtil.getBytesByInt( value, true );
	}

	/**
	 * @param value
	 * @param bigEndian
	 * @return
	 */
	private static byte[] getBytesByInt( int value, boolean bigEndian ) {
		ByteBuffer bb = ByteBuffer.allocate( 4 );
		if ( !bigEndian )
			bb.order( ByteOrder.LITTLE_ENDIAN );
		bb.putInt( value );
        return bb.array( );
	}

	/**
	 * @param bs
	 * @return
	 */
	public static long readLongBig( byte[] bs ) {
		return ByteUtil.readLongFromBytes( bs, true );
	}

	/**
	 * @param bs
	 * @return
	 */
	public static long readLongLittle( byte[] bs ) {
		return ByteUtil.readLongFromBytes( bs, false );
	}

	/**
	 * @param bs
	 * @param bigEndian
	 * @return
	 */
	private static long readLongFromBytes( byte[] bs, boolean bigEndian ) {
		if ( bs == null )
			return -1;
		long ret = 0;
		int pos;
		for ( int i = 0; i < bs.length && i < 8; i++ ) {
			ret <<= 8;
			if ( bigEndian )
				pos = i;
			else
				pos = bs.length - 1 - i;
			ret |= bs[pos] & 0xFF;
		}
		return ret;
	}

	/**
	 * @param bs
	 * @return
	 */
	public static int readIntBig( byte[] bs ) {
		return ByteUtil.readIntFromBytes( bs, true );
	}

	/**
	 * @param bs
	 * @return
	 */
	public static int readIntLittle( byte[] bs ) {
		return ByteUtil.readIntFromBytes( bs, false );
	}

	/**
	 * @param bs
	 * @param bigEndian
	 * @return
	 */
	private static int readIntFromBytes( byte[] bs, boolean bigEndian ) {
		if ( bs == null )
			return -1;
		int ret = 0;
		int pos;
		for ( int i = 0; i < bs.length && i < 4; i++ ) {
			ret <<= 8;
			if ( bigEndian )
				pos = i;
			else
				pos = bs.length - 1 - i;
			ret |= bs[pos] & 0xFF;
		}
		return ret;
	}

}